/*
 *   __               .__       .__  ._____.           
 * _/  |_  _______  __|__| ____ |  | |__\_ |__   ______
 * \   __\/  _ \  \/  /  |/ ___\|  | |  || __ \ /  ___/
 *  |  | (  <_> >    <|  \  \___|  |_|  || \_\ \\___ \ 
 *  |__|  \____/__/\_ \__|\___  >____/__||___  /____  >
 *                   \/       \/             \/     \/ 
 *
 * Copyright (c) 2006-2011 Karsten Schmidt
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * http://creativecommons.org/licenses/LGPL/2.1/
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */
package toxi.audio;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * <p>
 * Convert A-Law or u-Law byte stream into mono PCM byte stream
 * </p>
 * 
 * <code>
 * static AudioFormat alawformat= new AudioFormat(AudioFormat.Encoding.ALAW,8000,8,1,1,8000,false);
 * static AudioFormat ulawformat= new AudioFormat(AudioFormat.Encoding.ULAW,8000,8,1,1,8000,false);
 * </code>
 * <p>
 * PCM 8000.0 Hz, 16 bit, mono, SIGNED, little-endian
 * </p>
 * <code>static AudioFormat pcmformat = new AudioFormat(8000,16,1,true,false);</code>
 * 
 * <p>
 * From: Mathematical Tools in Signal Processing with C++ and Java Simulations
 * by Willi-Hans Steeb International School for Scientific Computing
 * </p>
 */
public class DecompressInputStream extends FilterInputStream {

    static private int[] alawtable = { 0x80ea, 0x80eb, 0x80e8, 0x80e9, 0x80ee,
            0x80ef, 0x80ec, 0x80ed, 0x80e2, 0x80e3, 0x80e0, 0x80e1, 0x80e6,
            0x80e7, 0x80e4, 0x80e5, 0x40f5, 0xc0f5, 0x40f4, 0xc0f4, 0x40f7,
            0xc0f7, 0x40f6, 0xc0f6, 0x40f1, 0xc0f1, 0x40f0, 0xc0f0, 0x40f3,
            0xc0f3, 0x40f2, 0xc0f2, 0x00aa, 0x00ae, 0x00a2, 0x00a6, 0x00ba,
            0x00be, 0x00b2, 0x00b6, 0x008a, 0x008e, 0x0082, 0x0086, 0x009a,
            0x009e, 0x0092, 0x0096, 0x00d5, 0x00d7, 0x00d1, 0x00d3, 0x00dd,
            0x00df, 0x00d9, 0x00db, 0x00c5, 0x00c7, 0x00c1, 0x00c3, 0x00cd,
            0x00cf, 0x00c9, 0x00cb, 0xa8fe, 0xb8fe, 0x88fe, 0x98fe, 0xe8fe,
            0xf8fe, 0xc8fe, 0xd8fe, 0x28fe, 0x38fe, 0x08fe, 0x18fe, 0x68fe,
            0x78fe, 0x48fe, 0x58fe, 0xa8ff, 0xb8ff, 0x88ff, 0x98ff, 0xe8ff,
            0xf8ff, 0xc8ff, 0xd8ff, 0x28ff, 0x38ff, 0x08ff, 0x18ff, 0x68ff,
            0x78ff, 0x48ff, 0x58ff, 0xa0fa, 0xe0fa, 0x20fa, 0x60fa, 0xa0fb,
            0xe0fb, 0x20fb, 0x60fb, 0xa0f8, 0xe0f8, 0x20f8, 0x60f8, 0xa0f9,
            0xe0f9, 0x20f9, 0x60f9, 0x50fd, 0x70fd, 0x10fd, 0x30fd, 0xd0fd,
            0xf0fd, 0x90fd, 0xb0fd, 0x50fc, 0x70fc, 0x10fc, 0x30fc, 0xd0fc,
            0xf0fc, 0x90fc, 0xb0fc, 0x8015, 0x8014, 0x8017, 0x8016, 0x8011,
            0x8010, 0x8013, 0x8012, 0x801d, 0x801c, 0x801f, 0x801e, 0x8019,
            0x8018, 0x801b, 0x801a, 0xc00a, 0x400a, 0xc00b, 0x400b, 0xc008,
            0x4008, 0xc009, 0x4009, 0xc00e, 0x400e, 0xc00f, 0x400f, 0xc00c,
            0x400c, 0xc00d, 0x400d, 0x0056, 0x0052, 0x005e, 0x005a, 0x0046,
            0x0042, 0x004e, 0x004a, 0x0076, 0x0072, 0x007e, 0x007a, 0x0066,
            0x0062, 0x006e, 0x006a, 0x002b, 0x0029, 0x002f, 0x002d, 0x0023,
            0x0021, 0x0027, 0x0025, 0x003b, 0x0039, 0x003f, 0x003d, 0x0033,
            0x0031, 0x0037, 0x0035, 0x5801, 0x4801, 0x7801, 0x6801, 0x1801,
            0x0801, 0x3801, 0x2801, 0xd801, 0xc801, 0xf801, 0xe801, 0x9801,
            0x8801, 0xb801, 0xa801, 0x5800, 0x4800, 0x7800, 0x6800, 0x1800,
            0x0800, 0x3800, 0x2800, 0xd800, 0xc800, 0xf800, 0xe800, 0x9800,
            0x8800, 0xb800, 0xa800, 0x6005, 0x2005, 0xe005, 0xa005, 0x6004,
            0x2004, 0xe004, 0xa004, 0x6007, 0x2007, 0xe007, 0xa007, 0x6006,
            0x2006, 0xe006, 0xa006, 0xb002, 0x9002, 0xf002, 0xd002, 0x3002,
            0x1002, 0x7002, 0x5002, 0xb003, 0x9003, 0xf003, 0xd003, 0x3003,
            0x1003, 0x7003, 0x5003, };

    static private int[] ulawtable = { 0x8482, 0x8486, 0x848a, 0x848e, 0x8492,
            0x8496, 0x849a, 0x849e, 0x84a2, 0x84a6, 0x84aa, 0x84ae, 0x84b2,
            0x84b6, 0x84ba, 0x84be, 0x84c1, 0x84c3, 0x84c5, 0x84c7, 0x84c9,
            0x84cb, 0x84cd, 0x84cf, 0x84d1, 0x84d3, 0x84d5, 0x84d7, 0x84d9,
            0x84db, 0x84dd, 0x84df, 0x04e1, 0x04e2, 0x04e3, 0x04e4, 0x04e5,
            0x04e6, 0x04e7, 0x04e8, 0x04e9, 0x04ea, 0x04eb, 0x04ec, 0x04ed,
            0x04ee, 0x04ef, 0x04f0, 0xc4f0, 0x44f1, 0xc4f1, 0x44f2, 0xc4f2,
            0x44f3, 0xc4f3, 0x44f4, 0xc4f4, 0x44f5, 0xc4f5, 0x44f6, 0xc4f6,
            0x44f7, 0xc4f7, 0x44f8, 0xa4f8, 0xe4f8, 0x24f9, 0x64f9, 0xa4f9,
            0xe4f9, 0x24fa, 0x64fa, 0xa4fa, 0xe4fa, 0x24fb, 0x64fb, 0xa4fb,
            0xe4fb, 0x24fc, 0x64fc, 0x94fc, 0xb4fc, 0xd4fc, 0xf4fc, 0x14fd,
            0x34fd, 0x54fd, 0x74fd, 0x94fd, 0xb4fd, 0xd4fd, 0xf4fd, 0x14fe,
            0x34fe, 0x54fe, 0x74fe, 0x8cfe, 0x9cfe, 0xacfe, 0xbcfe, 0xccfe,
            0xdcfe, 0xecfe, 0xfcfe, 0x0cff, 0x1cff, 0x2cff, 0x3cff, 0x4cff,
            0x5cff, 0x6cff, 0x7cff, 0x88ff, 0x90ff, 0x98ff, 0xa0ff, 0xa8ff,
            0xb0ff, 0xb8ff, 0xc0ff, 0xc8ff, 0xd0ff, 0xd8ff, 0xe0ff, 0xe8ff,
            0xf0ff, 0xf8ff, 0x0000, 0x7c7d, 0x7c79, 0x7c75, 0x7c71, 0x7c6d,
            0x7c69, 0x7c65, 0x7c61, 0x7c5d, 0x7c59, 0x7c55, 0x7c51, 0x7c4d,
            0x7c49, 0x7c45, 0x7c41, 0x7c3e, 0x7c3c, 0x7c3a, 0x7c38, 0x7c36,
            0x7c34, 0x7c32, 0x7c30, 0x7c2e, 0x7c2c, 0x7c2a, 0x7c28, 0x7c26,
            0x7c24, 0x7c22, 0x7c20, 0xfc1e, 0xfc1d, 0xfc1c, 0xfc1b, 0xfc1a,
            0xfc19, 0xfc18, 0xfc17, 0xfc16, 0xfc15, 0xfc14, 0xfc13, 0xfc12,
            0xfc11, 0xfc10, 0xfc0f, 0x3c0f, 0xbc0e, 0x3c0e, 0xbc0d, 0x3c0d,
            0xbc0c, 0x3c0c, 0xbc0b, 0x3c0b, 0xbc0a, 0x3c0a, 0xbc09, 0x3c09,
            0xbc08, 0x3c08, 0xbc07, 0x5c07, 0x1c07, 0xdc06, 0x9c06, 0x5c06,
            0x1c06, 0xdc05, 0x9c05, 0x5c05, 0x1c05, 0xdc04, 0x9c04, 0x5c04,
            0x1c04, 0xdc03, 0x9c03, 0x6c03, 0x4c03, 0x2c03, 0x0c03, 0xec02,
            0xcc02, 0xac02, 0x8c02, 0x6c02, 0x4c02, 0x2c02, 0x0c02, 0xec01,
            0xcc01, 0xac01, 0x8c01, 0x7401, 0x6401, 0x5401, 0x4401, 0x3401,
            0x2401, 0x1401, 0x0401, 0xf400, 0xe400, 0xd400, 0xc400, 0xb400,
            0xa400, 0x9400, 0x8400, 0x7800, 0x7000, 0x6800, 0x6000, 0x5800,
            0x5000, 0x4800, 0x4000, 0x3800, 0x3000, 0x2800, 0x2000, 0x1800,
            0x1000, 0x0800, 0x0000, };

    private int[] table = null;

    public DecompressInputStream(InputStream in, boolean useALaw)
            throws IOException {
        super(in);
        table = (useALaw) ? alawtable : ulawtable;
    }

    public int read() throws IOException {
        throw new IOException(getClass().getName()
                + ".read() :\n\tDo not support simple read().");
    }

    public int read(byte[] b) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte[] b, int off, int len) throws IOException {
        byte[] inb;
        int value;

        inb = new byte[len >> 1]; // get A-Law or u-Law bytes
        len = in.read(inb);
        if (len == -1) {
            return -1;
        }

        for (int i = 0; i < len; i++) {
            value = table[inb[i] & 0x00FF];
            b[off++] = (byte) ((value >> 8) & 0x00FF); // little-endian
            b[off++] = (byte) (value & 0x00FF);
        }
        return len << 1;
    }
}